/*
 * Copyright (c) 2012 Banaanvraag
 * MIT Licence
 */
package banaanvraag.tools.arrays;

import banaanvraag.tools.interfaces.Byteable;

/**
 * Extensive list of functions for converting between byte arrays and Java primitives.
 * @author Luc
 */
public class ByteArray {
    
    /**
     * Convert a byte to a byte array. Just for completeness' sake.
     * @param number The byte to put in the array
     * @return The byte array (size = 1) containing the byte
     */
    public static byte[] toArray(byte number) {
        return new byte[] {number};
    }
    
    /**
     * Convert a short to a byte array.
     * @param number The short to put in the array
     * @return The byte array (size = 2) containing the byte
     */
    public static byte[] toArray(short number) {
        return new byte[] {
            (byte)((number >> 8) & 0xff),
            (byte)(number)
        };
    }
    
    /**
     * Convert an int to a byte array
     * @param number The int to put in the array
     * @return The byte array (size = 4) containing the int
     */
    public static byte[] toArray(int number) {
        return new byte[] {
            (byte)(number >> 24 & 0xff),
            (byte)(number >> 16 & 0xff),
            (byte)(number >> 8 & 0xff),
            (byte)(number)
        };
    }
    
    /**
     * Convert a long to a byte array
     * @param number The long to put in the array
     * @return The byte array (size = 8) containing the long
     */
    public static byte[] toArray(long number) {
        return new byte[] {
            (byte)(number >> 56 & 0xff),
            (byte)(number >> 48 & 0xff),
            (byte)(number >> 40 & 0xff),
            (byte)(number >> 32 & 0xff),
            (byte)(number >> 24 & 0xff),
            (byte)(number >> 16 & 0xff),
            (byte)(number >> 8 & 0xff),
            (byte)(number)
        };
    }
    
    /**
     * Convert a float to a byte array
     * @param number The float to put in the array
     * @return The byte array (size = 4) containing the array
     */
    public static byte[] toArray(float number) {
        return toArray(Float.floatToRawIntBits(number));
    }
    
    /**
     * Convert a double to a byte array
     * @param number The double to put in the array
     * @return The byte array (size = 8) containing the array
     */
    public static byte[] toArray(double number) {
        return toArray(Double.doubleToRawLongBits(number));
    }
    
    /**
     * Convert a char to a byte array
     * @param number The char to put in the array
     * @return The byte array (size = 2) containing the char
     */
    public static byte[] toArray(char number) {
        return new byte[] {
            (byte)((number >> 8 & 0xff)),
            (byte)((number & 0xff))
        };
    }
    
    /**
     * Convert a boolean to a byte array
     * @param value The boolean to put in the array
     * @return The byte array (size = 1) containing the boolean (0x00 = false, 0xff = true)
     */
    public static byte[] toArray(boolean value) {
        return value ? new byte[]{(byte)0xff} : new byte[]{(byte)0x00};
    }
    
    /**
     * Convert an object to a byte array if it's Byteable using the Byteable's toByteArray() function.
     * @param obj The object to put in the byte array
     * @return The byte array (variable size) containing everything the object wants to store
     * @see Byteable
     */
    public static byte[] toArray(Object obj) {
        if(obj instanceof Byteable) {
            return ((Byteable)obj).toByteArray();
        }
        return new byte[]{0x00};
    }
    
    /**
     * Convert a string to a byte array using the String's functions
     * @param value The string to put in the byte array
     * @return The byte array (variable size) containing the String's bytes
     */
    public static byte[] toArray(String value) {
        return value.getBytes();
    }
    
    /**
     * Take a byte array and create a byte from it. Doesn't check for array size! (assumes size = 1)
     * @param array The byte array
     * @return The byte in the byte array
     */
    public static byte toByte(byte[] array) {
        return (array[0]);
    }
    
    /**
     * Take a byte array and create a short from it. Doesn't check for array size! (assumes size = 2)
     * @param array The byte array
     * @return The short in the byte array
     */
    public static short toShort(byte[] array) {
        return (short)
                (((array[0] & 0xff) << 8)
                | (array[1] & 0xff));
    }
    
    /**
     * Take a byte arrray and create an int from it. Doesn't check for array size! (assumes size = 4)
     * @param array The byte array
     * @return The int in the byte array
     */
    public static int toInt(byte[] array) {
        return  (array[0] & 0xff) << 24
               |(array[1] & 0xff) << 16
               |(array[2] & 0xff) << 8
               |(array[3] & 0xff);
    }
    
    /**
     * Take a byte array and create a long from it. Doesn't check for array size! (assumes size = 8)
     * @param array The byte array
     * @return The long in the byte array
     */
    public static long toLong(byte[] array) {
        return (long)
                ((long)(array[0] & 0xff) << 56
                |(long)(array[1] & 0xff) << 48
                |(long)(array[2] & 0xff) << 40
                |(long)(array[3] & 0xff) << 32
                |(long)(array[4] & 0xff) << 24
                |(long)(array[5] & 0xff) << 16
                |(long)(array[6] & 0xff) << 8
                |(long)(array[7] & 0xff));
    }
    
    /**
     * Take a byte array and create a float from it. Doesn't check for array size! (assumes size = 4)
     * @param array The byte array
     * @return The float in the byte array
     */
    public static float toFloat(byte[] array) {
        return Float.intBitsToFloat(toInt(array));
    }
    
    /**
     * Take a byte array and create a double from it. Doesn't check for array size! (assumes size = 8)
     * @param array The byte array
     * @return The double in the byte array
     */
    public static double toDouble(byte[] array) {
        return Double.longBitsToDouble(toLong(array));
    }
    
    /**
     * Take a byte array and create a char from it. Doesn't check for array size! (assumes size = 2)
     * @param array The byte array
     * @return The char in the byte array
     */
    public static char toChar(byte[] array) {
        return (char)((array[0] & 0xff) << 8
                |(array[1] & 0xff));
    }
    
    /**
     * Take a byte array and create a boolean from it. Doesn't check array size! (assumes size = 1)
     * @param array The byte array
     * @return The boolean in the byte array
     */
    public static boolean toBoolean(byte[] array) {
        return (array[0] == 0xff);
    }
    
    /**
     * Take a byte array and create a String from it.
     * @param array The byte array
     * @return The String in the byte array
     */
    public static String toString(byte[] array) {
        return new String(array);
    }
    
    /**
     * Takes all values in an array up to a specified index.
     * @param array The array to limit
     * @param limit The size of the array to limit to. Key is limit - 1.
     * @return The array of size [limit]
     */
    public static byte[] limitArray(byte[] array, int limit) {
        int size = array.length <= limit ? array.length : limit;
        byte[] ret = new byte[size];
        int i = 0;
        while(i < size) {
            ret[i] = array[i];
            i++;
        }
        return ret;
    }
    
    /**
     * Converts a byte[] array to a Byte[] array
     * @param array The byte[] array
     * @return The Byte[] array
     */
    public static Byte[] toObjectArray(byte[] array) {
        Byte[] ret = new Byte[array.length];
        int i = 0;
        while(i < array.length) {
            ret[i] = array[i];
            i++;
        }
        return ret;
    }
    
    /**
     * Converts a Byte[] array to a byte[] array
     * @param array The Byte[] array
     * @return The byte[] array
     */
    public static byte[] fromObjectArray(Byte[] array) {
        byte[] ret = new byte[array.length];
        int i = 0;
        while(i < array.length) {
            ret[i] = array[i];
            i++;
        }
        return ret;
    }
}
